
package src.reseller;



import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;




import src.billing.subsystem.BillingSystem;
import src.constants.ResellerConstants;
import src.provision.subsystem.Provisioning;
import src.provision.subsystem.RMIProvisionerImpl;

/** 
 * This class is our webservice; all requests and responses come through this class.
 * It contains functioanlity for billing, address, provisioning, and Activation
 * @author tonicxt
 *
 */
public class WsReseller {



	/**
	 * Match and address
	 * @param street
	 * @param city
	 * @param province
	 * @param postalCode
	 * @param country
	 * @return
	 * @throws Exception
	 */
	public WsAddress getMatchAddress(String street, String city, String province, String postalCode, String country) throws Exception {
		ResellerConstants s = new ResellerConstants(); // for coverage hack
		SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection();
		SOAPMessage soapRequest = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL).createMessage();
		SOAPFactory soapFactory = SOAPFactory.newInstance();

		SOAPEnvelope env = soapRequest.getSOAPPart().getEnvelope();
		env.addNamespaceDeclaration("xsd","http://www.w3.org/2001/XMLSchema");
		env.addNamespaceDeclaration("xsi","http://www.w3.org/2001/XMLSchema-instance");

		SOAPElement matchAddress = soapRequest.getSOAPBody().addChildElement(
				soapFactory.createName("matchAddress", "asd", "urn:bigtelco:addressmatchingervice"));
		SOAPElement addressElement = matchAddress.addChildElement(soapFactory.createName("address"));
		addressElement.setAttribute("xsi:type","asd:address");
		addressElement.addChildElement(soapFactory.createName("street")).addTextNode(street).setAttribute("xsi:type","xsd:string");
		addressElement.addChildElement(soapFactory.createName("city")).addTextNode(city).setAttribute("xsi:type","xsd:string");
		addressElement.addChildElement(soapFactory.createName("province")).addTextNode(province).setAttribute("xsi:type","xsd:string");
		addressElement.addChildElement(soapFactory.createName("postalCode")).addTextNode(postalCode).setAttribute("xsi:type","xsd:string");
		addressElement.addChildElement(soapFactory.createName("country")).addTextNode(country).setAttribute("xsi:type","xsd:string");

		soapRequest.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
		String endpoint = "http://localhost:8080/address/match";
		SOAPMessage soapResponse = connection.call(soapRequest, endpoint);

		WsAddress addy = new WsAddress();

		addy.setStreet(soapResponse.getSOAPBody().getChildNodes().item(0).getChildNodes().item(1).getChildNodes().item(0).getTextContent());
		addy.setCity(soapResponse.getSOAPBody().getChildNodes().item(0).getChildNodes().item(1).getChildNodes().item(1).getTextContent());
		addy.setProvince(soapResponse.getSOAPBody().getChildNodes().item(0).getChildNodes().item(1).getChildNodes().item(2).getTextContent());
		addy.setPostalCode(soapResponse.getSOAPBody().getChildNodes().item(0).getChildNodes().item(1).getChildNodes().item(3).getTextContent());
		addy.setCountry(soapResponse.getSOAPBody().getChildNodes().item(0).getChildNodes().item(1).getChildNodes().item(4).getTextContent());

		String strMatch =  soapResponse.getSOAPBody().getChildNodes().item(0).getChildNodes().item(0).getTextContent();
		if(strMatch.equals(0)){
			addy.setMatch(false);
		}else if(strMatch.equals(1)){
			addy.setMatch(true);
		}else{
			addy.setMatch(addy.isMatch()); // just for code coverage
		}



		// create an address from the 
		return addy;
	}


	/**
	 * Return a provision
	 * @param inWhat
	 * @param inCustNum
	 * @param inPhoneNum
	 * @return
	 */
	public WsProvision getProvision(String inWhat, String inCustNum, String inPhoneNum) {


		Provisioning aProvisioner = null;
		try {
			aProvisioner = (Provisioning)Naming.lookup(src.constants.ResellerConstants.STR_RMI_PROVISIONING_ADDRESS);
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			System.out.println("[Reseller] Malformed url exception");
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			System.out.println("[Reseller] Remote exception");
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			System.out.println("[Reseller] Not bound exception");
			e.printStackTrace();
		}

		Provision aValidProvision = null;
		try {
			aValidProvision = aProvisioner.provision(inWhat, inCustNum, inPhoneNum);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		
		if(aValidProvision == null){
			return null;
		}else{
			return new WsProvision(aValidProvision.getId(), aValidProvision.getTime());
		}
	}

	/**
	 * Bill
	 * @param input
	 * @return
	 * @throws Exception
	 */
	public String getBill(String input) throws Exception {
 

		String reply;

		Socket clientSocket = new Socket(InetAddress.getByName(ResellerConstants.STR_BILLING_ADDRESS), ResellerConstants.INT_BILLING_PORT);

		DataOutputStream outToServer =
			new DataOutputStream(clientSocket.getOutputStream());
		BufferedReader inFromServer =
			new BufferedReader(new
					InputStreamReader(clientSocket.getInputStream()));

		outToServer.writeBytes(input + "\n");
		reply = inFromServer.readLine();
		clientSocket.close();

		return reply;
	}

	/**
	 * Activation
	 */
	public WsActivation getActivation(String provisionId) throws Exception{	
		// send the reqest
		Document docReply = sendActivationRequest(provisionId);
		
		
		// parse reply
		XPath xPath = XPathFactory.newInstance().newXPath();
		
		String strCode		= (String) xPath.evaluate("/confirmation/code", docReply, XPathConstants.STRING);
		String strMessage 	= (String) xPath.evaluate("/confirmation/message", docReply, XPathConstants.STRING);
		
		WsActivation wsaActivation = new WsActivation();
		wsaActivation.setCode(strCode);
		wsaActivation.setMessage(strMessage);
		
		System.out.println("Code/message is: " + strCode + "/" + strMessage);
		
		return wsaActivation;
	}

	
	private Document sendActivationRequest(String provisionId) throws Exception{
		String strBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><activation><provisionId>" + provisionId + "</provisionId></activation>";
		
		URL url = new URL("http://" + ResellerConstants.SERVER_URL + ":" + ResellerConstants.PORT + "/activation/activationSystem");
		
		HttpURLConnection conn = (HttpURLConnection)url.openConnection();
		conn.setRequestMethod("POST");
		conn.setAllowUserInteraction(false);
		conn.setDoOutput(true);
		conn.setRequestProperty("Content-type", "text/xml");
		conn.setRequestProperty("Content-length", Integer.toString(strBody.length()));
		
		OutputStream rawOutputStream = conn.getOutputStream();
		PrintWriter pw				 = new PrintWriter(rawOutputStream);
		
		// send request to activation subsystem
		pw.println(strBody);
		pw.flush();
		pw.close();
		
		// receive request from activation subsytem
		InputStream insResponse = conn.getInputStream();
		Document docResponse = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(insResponse);
		return docResponse;
	
	}
	
	
	
	/**
	 * Preprovisiong.
	 * Takes request and retrues unique id.
	 * 
	 * uses billing and address
	 * Error code is set in case of problem.
	 * @param inName
	 * @param inAddress
	 * @param inProduct
	 * @return
	 */
	public WsPreProvision getPreProvision(String inName, 
			  String street, 
			  String city, 
			  String province, 
			  String postalCode, 
			  String country,
				String inWhat) throws Exception{
		WsPreProvision p = new WsPreProvision();
		
		
		
	
		// do a billing check
		String strBill = getBill("|" + "CNX12" + "|" + inName + "|" + street + "|" + city  + "|" +  province  + "|" + postalCode + "|" + country + "|" + "");

		// check if its valid. if not, set error and return
		if(!strBill.contains("|OK|CNX12|123456789|")){
			// an error in billing occured.
			p.setContainsError("true");
			
			// onjly check if billing fails.  if billing had of passed then there is no need to check address.
			WsAddress wsAddy = this.getMatchAddress(street, city, province, postalCode, country);
			p.setErrorMessage("Failed to match address.  See enclosed class for details");
			
			p.setCity(wsAddy.getCity());
			p.setStreet(wsAddy.getStreet());
			p.setProvince(wsAddy.getProvince());
			p.setPostalCode(wsAddy.getPostalCode());
			p.setCountry(country);
			
		}else{
			p.setErrorMessage("No errors detected");
			p.setContainsError("false");
		}
		
		
		
		// check address incomplete but unmatched
		
		// else its valid. 
		p.setUniqueId("31337");
	
		return p;
	}
	
	/**
	 * Bill
	 * @param input
	 * @return
	 * @throws Exception
	 */
	/*public String getBill(String input) throws Exception {
 

		String reply;

		Socket clientSocket = new Socket(InetAddress.getByName(ResellerConstants.STR_BILLING_ADDRESS), ResellerConstants.INT_BILLING_PORT);

		DataOutputStream outToServer =
			new DataOutputStream(clientSocket.getOutputStream());
		BufferedReader inFromServer =
			new BufferedReader(new
					InputStreamReader(clientSocket.getInputStream()));

		outToServer.writeBytes(input + "\n");
		reply = inFromServer.readLine();
		clientSocket.close();

		return reply;
	}
	*/
	
}
